package xdu.lz.stage5_jucUtils.chapter5_lock.condition;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created at 2019/10/19 0019 下午 9:48
 * <p>
 * 三个问题：
 * 1、不使用condition的通知和唤醒机制 ，只是用lock，能也实现生产一个消费一个，那么condition作用？
 * {@link Condition2} 如果不使用并且使用非公平锁，会导致生产或消费多次
 * 2、生产后进入condition.await   但是消费者此时能得到锁，await会释放锁吗？
 * 和Obj的wait机制一样，condition.await后会释放lock锁
 * 3、不使用lock只使用condition？
 * 不行,condition得在lock前提下使用，就像Obj.wait得在synchronized中使用一样
 */
public class ProduceConsumeCondition1 {

    private static final ReentrantLock lock = new ReentrantLock(true);

    private static final Condition condition = lock.newCondition();

    private static int data = 0;

    //默认是已经被消费了，也就是要生产
    private static volatile boolean hasConsume = true;

    private static void buildData() {
        try {
            lock.lock();
            //如果没有被消费 ，等待
            while (!hasConsume) {
                condition.await();
            }
            //else : hasConsume = false
            Thread.sleep(1);
            System.out.println("P:" + ++data);
            hasConsume = false;
            //notify
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    private static void useData() {
        try {
            lock.lock();
            //如果已经被消费过，则等待
            while (hasConsume) {
                condition.await();
            }
            //indicate: hasConsume false, consume data
            Thread.sleep(1);
            System.out.println(Thread.currentThread().getName() + " consume " + data);
            hasConsume = true;
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        new Thread(() -> {
            while (true) {
                buildData();
            }
        }).start();
        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                while (true) {
                    useData();
                }
            }, "consumer " + i).start();
        }
    }
}
